/***************************************************************************
 *   Copyright (C) 2008 by duanp   *
 *   duanp@163.com   *
 *          based  on  NetXRay  's  version  "mystar"          *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#include <iostream>
//#include <strstream>

#include "mystar.h"
#include "md5.h"

#define FILTER_STR "ether[12:2]=0x888e and ether dst %02x:%02x:%02x:%02x:%02x:%02x"
//#define FILTER_STR "ether[12:2]=0x888e and ether dst "

using namespace std;

StarAuth::StarAuth()
{
	authState=before_init;
	TextEdit=NULL;
	config=NULL;
}

StarAuth::~StarAuth()
{
}

StarAuth::StarAuth(StarConfig * conf ,QTextEdit *  qtext)
{	
	authState=before_init;
	TextEdit=qtext;
	config=conf;
	Init();
}

void StarAuth::OutPut(char * str)
{
	if(TextEdit!=NULL){
		//TextEdit->append(trUtf8(str));
		TextEdit->append(str);
	}
}

void StarAuth::SetConfig(StarConfig * conf)
{
	config=conf;
}

void StarAuth::SetOutPut(QTextEdit * qtext)
{
	TextEdit=qtext;
}

void StarAuth::Init()
{
	if(config==NULL) 
	{ cout<<"Please set config and output edittext first!"<<endl;
	return;
	}
	
	ptrLibnet=NULL;
	ptrPcap=NULL;
	serialNo.ulValue = 0x1000002a;        //the initial serial number, a magic number!
	
	//初始化 libnet  结构 
	char    l_errbuf[LIBNET_ERRBUF_SIZE];
	if((ptrLibnet=libnet_init(LIBNET_LINK, config->nic,l_errbuf))==NULL)
        {
		 cout<<"libnet_init error !:"<<l_errbuf<<endl; 		
		OutPut("nic  Init Error!!  Check it!");
		OutPut(l_errbuf);
		libnet_destroy(ptrLibnet);
		return ;
	}

	/*获取 本地 IP 地址*/
	if(!config->isFakeInUse)
	{
		u_int32_t                 l_ip=0x00000000;
		if((l_ip=libnet_get_ipaddr4(ptrLibnet))==0x00000000)
         	{
			 cout<<"unable to get ip address--ingored... :"<<libnet_geterror(ptrLibnet)<<endl;
			OutPut("get ip address--ingored");
			OutPut(libnet_geterror(ptrLibnet));
			 l_ip=0;
			libnet_destroy(ptrLibnet);
			return ;
		
		}
        	 memcpy(localIP,&l_ip,sizeof(localIP));
	}
	else  memcpy(localIP,config->fakeAddress,sizeof(localIP));

	/*获取本地网卡地址*/
	struct libnet_ether_addr  *l_ether_addr;	
  	if((l_ether_addr=libnet_get_hwaddr(ptrLibnet))==NULL)
      	{
		 cout<<"unable to get local mac address :"<<libnet_geterror(ptrLibnet)<<endl;		
		OutPut("unable to get local mac address");
		OutPut(libnet_geterror(ptrLibnet));
		libnet_destroy(ptrLibnet);
		return;
	};
	memcpy(localMac,l_ether_addr,sizeof(localMac));

	/*初始化 pcap  结构 */
	char   p_errbuf[PCAP_ERRBUF_SIZE];
	if((ptrPcap=pcap_open_live(config->nic,65536,0, 500, p_errbuf))==NULL)
      	{
		 cout<<"pcap_open_live error!: "<<p_errbuf<<endl ; 
		OutPut("pcap_open_live error!");
		OutPut(p_errbuf);
		libnet_destroy(ptrLibnet);
		return ;
	}

	/*获取 p_fd 便于后面设置端口监听*/
	p_fd=pcap_fileno(ptrPcap);

	/*获取网络地址，默认网关*/
	u_int32_t  p_netaddr,p_netmask;
	if(pcap_lookupnet(config->nic,&p_netaddr,&p_netmask,p_errbuf)==-1)	
	{
		 cout<<"unable to get netmask--igored..."<<p_errbuf<<endl ; p_netmask=0;
		OutPut("unable to get netmask--igored");
		OutPut(p_errbuf);
		
	}
	memcpy(localNetMask,&p_netmask,sizeof(localNetMask));

	/*设置DNS 和网关 不用获取*/
	memset(localDns,0,sizeof(localDns));
	memset(localGetway,0,sizeof(localGetway));
	
	CircleCheckGen();

	struct bpf_program  filter_code;
   	char                filter_buf[256];   
	/*字符串流Filter 等效于上面的snprintf*/
	/*
	ostrstream ostr(filter_buf,256,ios::out);
	ostr<<FILTER_STR<<localMac<<ends;
	*/	
	snprintf(filter_buf,sizeof(filter_buf),FILTER_STR,
	localMac[0],localMac[1],localMac[2],
	localMac[3],localMac[4],localMac[5]);	
 
	if(pcap_compile(ptrPcap, &filter_code,filter_buf, 0, p_netmask)==-1)
     	{ 
		cout<<"pcap_compile():"<< pcap_geterr(ptrPcap)<<endl; 
		OutPut("pcap_compile Error:");
		OutPut(pcap_geterr(ptrPcap));
		pcap_close(ptrPcap); libnet_destroy(ptrLibnet);
		return;
	}	
	if(pcap_setfilter(ptrPcap, &filter_code)==-1)
	{ 
		cout<<"pcap_setfilter():"<<pcap_geterr(ptrPcap)<<endl; 
		OutPut("pcap_setfilter Error:");
		OutPut(pcap_geterr(ptrPcap));
		pcap_close(ptrPcap); libnet_destroy(ptrLibnet);
		return;		
	}

	pcap_freecode(&filter_code); // avoid  memory-leak

	authState=init_ok;
}

void StarAuth::Run()
{
/*
	cout<<config->userName<<endl;
	cout<<config->passWord<<endl;
	cout<<config->nic<<endl; 
*/
	if(authState==before_init)	{
		pcap_close(ptrPcap); libnet_destroy(ptrLibnet);
		 return;
	}	

//	sigset_t     sigset_full;

	struct timespec timeout;
	timeout.tv_sec =1;   timeout.tv_nsec =0; // 1 second
	fd_set                          read_set;
	struct pcap_pkthdr     *pkt_hdr;
	const u_char              *pkt_data;

	bool isFirstReceive=1;
	int server_count=0;
	int name_count=0;
	int pass_count=0;

	//以下开始认证
	SendFindServerPacket(ptrLibnet); //发送第一个数据包

/*
	signal(SIGINT,sig_intr);  //We can exit with Ctrl+C
	sigfillset(&sigset_full);
	sigprocmask(SIG_BLOCK,&sigset_full,NULL); //block all signals.
*/	
	//等待接收一个数据包

	while(server_count<4&&name_count<4&&pass_count<4)
	{
		FD_ZERO(&read_set); 
		FD_SET(p_fd, &read_set);		


		//sigfillset(&sigset_full);
      		//sigdelset(&sigset_full,SIGINT);

		//wait with all signals(except SIGINT) blocked.
		//等待pcap文件描述符就绪, p_fd+1表示 查找范围最后一个为要阻塞的信号

		bool is_time_out=0;
		//int result=pselect(p_fd+1,&read_set,NULL,NULL,&timeout,&sigset_full);
		int result=pselect(p_fd+1,&read_set,NULL,NULL,&timeout,NULL);
		switch( result ){
			// SIGINT中断
			case -1: { return;}
			//Time Out 
			case 0:{is_time_out=1;break;}
		}

		if(is_time_out){
			switch( authState ){
				case init_ok: { server_count++;SendFindServerPacket(ptrLibnet); break; }
				case server_ok:{ name_count++;SendNamePacket(ptrLibnet,pkt_data); break; }
				case name_ok:{ pass_count++;SendPasswordPacket(ptrLibnet,pkt_data); break; }
				default :break;
			}
			//没有受到报文,继续主循环
			continue;
		}   
		
		//分析受到的数据包

		//Here return value of pcap_net_ex must be 1
		if((pcap_next_ex(ptrPcap,&pkt_hdr,&pkt_data))!=1) continue;
		//收到的第二个及其以后的有效packet的源MAC必须等于头次收到的有效分组的源MAC
		if ((!isFirstReceive)&&(memcmp(destMac,pkt_data+6,6)!=0)) continue;
		
		switch( pkt_data[0x12] )        //分析EAP包类型
		{
			case 0x01:        //表示请求
				switch( pkt_data[0x16] )
				{
					case 0x01:   //type 1,以用户名应答
						if(authState!=init_ok) continue;  //包不逢时,继续主循环
						authState=server_ok;
						cout<<"Server found, requesting user name..."<<endl;
						OutPut("Server found, requesting user name...");
						if (isFirstReceive) //获得服务器的MAC地址
						{ memcpy( destMac, pkt_data+6, 6); isFirstReceive=0;}
						name_count++;
						SendNamePacket(ptrLibnet, pkt_data);
						break;
					case 0x04:   //type 4,，以MD5加密密码得到的值应答
						if(authState!=server_ok) continue;
						authState=pass_ok;
						cout<<"User name ok, requesting password..."<<endl;
						OutPut("User name ok, requesting password....");
						pass_count++;
						SendPasswordPacket(ptrLibnet, pkt_data);
						break;
				}
				break;
			case 0x03:	{    //认证成功

					if(authState!=pass_ok) continue;
					authState=auth_ok;
					cout<<" Password ok, authentication SUCCESS!!!"<<endl;
					OutPut("Password ok, authentication SUCCESS!!!");
			
					if (config->echoInterval<=0) return; //user has echo disabled
					
					u_int16_t       offset;
					Union32	     uTemp;
					//uTemp.ulValue = *(((u_long *)(pkt_data+0x9d)));
					offset=ntohs( *((u_int16_t*)(pkt_data+0x10)) );
					uTemp.ulValue = *((u_int32_t *)(pkt_data+(0x11+offset)-0x08));
					key.btValue[0] = ByteTransform(uTemp.btValue[3]);
					key.btValue[1] = ByteTransform(uTemp.btValue[2]);
					key.btValue[2] = ByteTransform(uTemp.btValue[1]);
					key.btValue[3] = ByteTransform(uTemp.btValue[0]);					
					//认证结束
					//pcap_close(ptrPcap); libnet_destroy(ptrLibnet);
					return;
				}

			case 0x04:       { //认证失败(用户名或密码错误/不在上网时段内/重复上网等)

				if((authState==init_ok)) continue;  //一开始就受到这个包
				authState=auth_error;
				
				char   msgBuf[256];
				char   *pmsgBuf;
				uint	msgLen=ntohs( *((u_int16_t*)(pkt_data+0x10)) )-10;
				if (msgLen>0)
				{
					if(msgLen>=(sizeof(msgBuf)-1)) msgLen=sizeof(msgBuf)-1;
					memset(msgBuf,'\0',sizeof(msgBuf));
					memcpy(msgBuf, pkt_data+0x1c, msgLen);
					pmsgBuf=msgBuf;
					//remove the leanding "\r\n" which seems alway to exist!
					if((msgLen>2)&&(msgBuf[0]==0xd)&&(msgBuf[1]==0xa)) pmsgBuf+=2;
				}
				else { pmsgBuf=""; } //这个估计是服务器告知静默或确认断网的包
					
				cout<<"Authenticaton failed!!!"<<pmsgBuf<<endl;  
				OutPut("Authenticaton failed!!!");

				//SendEndCertPacket(ptrLibnet);	
				//pcap_close(ptrPcap); libnet_destroy(ptrLibnet);
				return;
				break; //should never come here
			}

		}// end switch
		
	} // end  while();
}


void StarAuth::RunEcho()
{
	SendEchoPacket(ptrLibnet);
}

void StarAuth::RunBye()
{
       SendEndCertPacket(ptrLibnet);
}

//A transformation of one-byte-for-one-byte
unsigned char   StarAuth::ByteTransform(unsigned char bytein){
  int a=0,b=0,c=0,d=0,iRt;

  a=bytein;
  c=a;
  d=a;
  c&=0x40;
  b=a;
  d>>=2;
  c|=d;
  d=a;
  c>>=2;
  d&=0x20;
  c|=d;
  d=a;
  c>>=2;
  d&=0x10;
  c|=d;

  d=a;
  d&=2;
  b<<=2;
  d|=b;
  b=a;
  d<<=2;
  b&=4;
  a&=8;
  d|=b;
  d<<=2;
  d|=a;

  c>>=1;
  d<<=1;
  c|=d;
  iRt=(~c)&0xff;
  return iRt;
}

//那帮家伙们，单靠这个算法就想区别实达客户端和非实达客户端 -_- !!
void StarAuth::CircleCheckGen (void){
  static unsigned char Table[]=
  {
    0x00,0x00,0x21,0x10,0x42,0x20,0x63,0x30,0x84,0x40,0xA5,0x50,0xC6,0x60,0xE7,0x70,
    0x08,0x81,0x29,0x91,0x4A,0xA1,0x6B,0xB1,0x8C,0xC1,0xAD,0xD1,0xCE,0xE1,0xEF,0xF1,
    0x31,0x12,0x10,0x02,0x73,0x32,0x52,0x22,0xB5,0x52,0x94,0x42,0xF7,0x72,0xD6,0x62,
    0x39,0x93,0x18,0x83,0x7B,0xB3,0x5A,0xA3,0xBD,0xD3,0x9C,0xC3,0xFF,0xF3,0xDE,0xE3,
    0x62,0x24,0x43,0x34,0x20,0x04,0x01,0x14,0xE6,0x64,0xC7,0x74,0xA4,0x44,0x85,0x54,
    0x6A,0xA5,0x4B,0xB5,0x28,0x85,0x09,0x95,0xEE,0xE5,0xCF,0xF5,0xAC,0xC5,0x8D,0xD5,
    0x53,0x36,0x72,0x26,0x11,0x16,0x30,0x06,0xD7,0x76,0xF6,0x66,0x95,0x56,0xB4,0x46,
    0x5B,0xB7,0x7A,0xA7,0x19,0x97,0x38,0x87,0xDF,0xF7,0xFE,0xE7,0x9D,0xD7,0xBC,0xC7,
    0xC4,0x48,0xE5,0x58,0x86,0x68,0xA7,0x78,0x40,0x08,0x61,0x18,0x02,0x28,0x23,0x38,
    0xCC,0xC9,0xED,0xD9,0x8E,0xE9,0xAF,0xF9,0x48,0x89,0x69,0x99,0x0A,0xA9,0x2B,0xB9,
    0xF5,0x5A,0xD4,0x4A,0xB7,0x7A,0x96,0x6A,0x71,0x1A,0x50,0x0A,0x33,0x3A,0x12,0x2A,
    0xFD,0xDB,0xDC,0xCB,0xBF,0xFB,0x9E,0xEB,0x79,0x9B,0x58,0x8B,0x3B,0xBB,0x1A,0xAB,
    0xA6,0x6C,0x87,0x7C,0xE4,0x4C,0xC5,0x5C,0x22,0x2C,0x03,0x3C,0x60,0x0C,0x41,0x1C,
    0xAE,0xED,0x8F,0xFD,0xEC,0xCD,0xCD,0xDD,0x2A,0xAD,0x0B,0xBD,0x68,0x8D,0x49,0x9D,
    0x97,0x7E,0xB6,0x6E,0xD5,0x5E,0xF4,0x4E,0x13,0x3E,0x32,0x2E,0x51,0x1E,0x70,0x0E,
    0x9F,0xFF,0xBE,0xEF,0xDD,0xDF,0xFC,0xCF,0x1B,0xBF,0x3A,0xAF,0x59,0x9F,0x78,0x8F,
    0x88,0x91,0xA9,0x81,0xCA,0xB1,0xEB,0xA1,0x0C,0xD1,0x2D,0xC1,0x4E,0xF1,0x6F,0xE1,
    0x80,0x10,0xA1,0x00,0xC2,0x30,0xE3,0x20,0x04,0x50,0x25,0x40,0x46,0x70,0x67,0x60,
    0xB9,0x83,0x98,0x93,0xFB,0xA3,0xDA,0xB3,0x3D,0xC3,0x1C,0xD3,0x7F,0xE3,0x5E,0xF3,
    0xB1,0x02,0x90,0x12,0xF3,0x22,0xD2,0x32,0x35,0x42,0x14,0x52,0x77,0x62,0x56,0x72,
    0xEA,0xB5,0xCB,0xA5,0xA8,0x95,0x89,0x85,0x6E,0xF5,0x4F,0xE5,0x2C,0xD5,0x0D,0xC5,
    0xE2,0x34,0xC3,0x24,0xA0,0x14,0x81,0x04,0x66,0x74,0x47,0x64,0x24,0x54,0x05,0x44,
    0xDB,0xA7,0xFA,0xB7,0x99,0x87,0xB8,0x97,0x5F,0xE7,0x7E,0xF7,0x1D,0xC7,0x3C,0xD7,
    0xD3,0x26,0xF2,0x36,0x91,0x06,0xB0,0x16,0x57,0x66,0x76,0x76,0x15,0x46,0x34,0x56,
    0x4C,0xD9,0x6D,0xC9,0x0E,0xF9,0x2F,0xE9,0xC8,0x99,0xE9,0x89,0x8A,0xB9,0xAB,0xA9,
    0x44,0x58,0x65,0x48,0x06,0x78,0x27,0x68,0xC0,0x18,0xE1,0x08,0x82,0x38,0xA3,0x28,
    0x7D,0xCB,0x5C,0xDB,0x3F,0xEB,0x1E,0xFB,0xF9,0x8B,0xD8,0x9B,0xBB,0xAB,0x9A,0xBB,
    0x75,0x4A,0x54,0x5A,0x37,0x6A,0x16,0x7A,0xF1,0x0A,0xD0,0x1A,0xB3,0x2A,0x92,0x3A,
    0x2E,0xFD,0x0F,0xED,0x6C,0xDD,0x4D,0xCD,0xAA,0xBD,0x8B,0xAD,0xE8,0x9D,0xC9,0x8D,
    0x26,0x7C,0x07,0x6C,0x64,0x5C,0x45,0x4C,0xA2,0x3C,0x83,0x2C,0xE0,0x1C,0xC1,0x0C,
    0x1F,0xEF,0x3E,0xFF,0x5D,0xCF,0x7C,0xDF,0x9B,0xAF,0xBA,0xBF,0xD9,0x8F,0xF8,0x9F,
    0x17,0x6E,0x36,0x7E,0x55,0x4E,0x74,0x5E,0x93,0x2E,0xB2,0x3E,0xD1,0x0E,0xF0,0x1E
  };
  static unsigned char sCircleBase[0x15]=
  {
    0x00,0x00,0x13,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00
  };
  int iCircle=0x15;
  int i,ax=0,bx=0,dx=0;

  sCircleBase[0x05] = localIP[0];
  sCircleBase[0x06] = localIP[1];
  sCircleBase[0x07] = localIP[2];
  sCircleBase[0x08] = localIP[3];
  sCircleBase[0x09] = localNetMask[0];
  sCircleBase[0x0a] = localNetMask[1];
  sCircleBase[0x0b] = localNetMask[2];
  sCircleBase[0x0c] = localNetMask[3];
  sCircleBase[0x0d] = localGetway[0];
  sCircleBase[0x0e] = localGetway[1];
  sCircleBase[0x0f] = localGetway[2];
  sCircleBase[0x10] = localGetway[3];
  sCircleBase[0x11] = localDns[0];
  sCircleBase[0x12] = localDns[1];
  sCircleBase[0x13] = localDns[2];
  sCircleBase[0x14] = localDns[3];

  for ( i=0 ; i<iCircle ; i++ )
    {
      dx = ax;
      bx = 0;
      bx = (bx&0xff00) | sCircleBase[i]; // add "( )" by cdx
      dx &= 0xffff;
      dx >>= 8;
      dx ^= bx;
      bx = 0;
      bx &= 0x00ff;
      bx |= (ax&0xff)<<8;

      ax = Table[dx*2] | Table[dx*2+1]<<8;
      ax ^= bx;
    }
  circleCheck[0] = (unsigned char) ((ax&0xff00)>>8);
  circleCheck[1] = (unsigned char) (ax&0x00ff);
}

void StarAuth::FillNetParamater(unsigned char ForFill[]){

  ForFill[ 0] = ByteTransform( localIP[0] );
  ForFill[ 1] = ByteTransform( localIP[1] );
  ForFill[ 2] = ByteTransform( localIP[2] );
  ForFill[ 3] = ByteTransform( localIP[3] );
  ForFill[ 4] = ByteTransform( localNetMask[0] );
  ForFill[ 5] = ByteTransform( localNetMask[1] );
  ForFill[ 6] = ByteTransform( localNetMask[2] );
  ForFill[ 7] = ByteTransform( localNetMask[3] );
  ForFill[ 8] = ByteTransform( localGetway[0] );
  ForFill[ 9] = ByteTransform( localGetway[1] );
  ForFill[10] = ByteTransform( localGetway[2] );
  ForFill[11] = ByteTransform( localGetway[3] );
  ForFill[12] = ByteTransform( localDns[0] );
  ForFill[13] = ByteTransform( localDns[1] );
  ForFill[14] = ByteTransform( localDns[2] );
  ForFill[15] = ByteTransform( localDns[3] );
  ForFill[16] = ByteTransform( circleCheck[0] );
  ForFill[17] = ByteTransform( circleCheck[1] );
}

int StarAuth::SendFindServerPacket(libnet_t *l){
  static uint8_t broadPackage[0x3E8] =          //广播包，用于寻找服务器
  {
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x88,0x8E,0x01,0x01,
    0x00,0x00,0xFF,0xFF,0x37,0x77,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x15,0x00,0x00,0x13,0x11,0x38,0x30,0x32,
    0x31,0x78,0x2E,0x65,0x78,0x65,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x1F,0x00,
    0x00,0x00,0x00,0x00,0x13,0x11,0x00,0x28,0x1A,0x28,0x00,0x00,0x13,0x11,0x17,0x22,
    0x92,0x68,0x64,0x66,0x92,0x94,0x62,0x66,0x91,0x93,0x95,0x62,0x93,0x93,0x91,0x94,
    0x64,0x61,0x64,0x64,0x65,0x66,0x68,0x94,0x98,0xA7,0x61,0x67,0x65,0x67,0x9C,0x6B
  };

  uint8_t StandardAddr[] = {0x01,0x80,0xC2,0x00,0x00,0x03};
  uint8_t StarAddr[]     = {0x01,0xD0,0xF8,0x00,0x00,0x03};

  if (config->authMode==1) memcpy(broadPackage,StarAddr,6);
  else memcpy( broadPackage, StandardAddr, 6 );
  memcpy( broadPackage+6, localMac, 6 );   //填充MAC地址

  FillNetParamater( &broadPackage[0x17] );

  cout<<">> Searching for server..."<<endl;
  OutPut(">> Searching for server...");

  return (libnet_write_link(l,broadPackage, 0x3E8)==0x3E8)?0:-1;
}

int StarAuth::SendNamePacket(libnet_t *l, const unsigned char  *pkt_data){
  static uint8_t ackPackage[0x3E8] =          //应答包，包括用户名和MD5
  {
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x88,0x8E,0x01,0x00,
    0x00,0x0D,0x02,0x01,0x00,0x0D,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,
    0xFF,0x37,0x77,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x13,0x11,0x38,0x30,0x32,0x31,0x78,0x2E,
    0x65,0x78,0x65,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
  };

  int nameLen;

  nameLen=strlen(config->userName);
  memcpy(ackPackage,this->destMac,6);  //将目的MAC地址填入组织回复的包
  memcpy(ackPackage+6,this->localMac,6);  //将本机MAC地址填入组织回复的包
  ackPackage[0x12]=0x02;            //code,2代表应答
  ackPackage[0x13]=pkt_data[0x13];  //id, HERE as if it's alway 1 from ShiDa ??
  *(short *)(ackPackage+0x10) = htons((short)(5+nameLen));//len
  *(short *)(ackPackage+0x14) = *(short *)(ackPackage+0x10);//len

  memcpy(ackPackage+0x17,config->userName,nameLen); //填入用户名
  cout<<">> Sending user name..."<<endl;
  OutPut(">> Sending user name");
  return (libnet_write_link(l,ackPackage, 0x3E8)==0x3E8)?0:-1;
}

int StarAuth::SendPasswordPacket(libnet_t *l,const unsigned char *pkt_data){
  static uint8_t ackPackage[0x3E8] =          //应答包，包括用户名和MD5
  {
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x88,0x8E,0x01,0x00,
    0x00,0x0D,0x02,0x01,0x00,0x0D,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,
    0xFF,0x37,0x77,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x13,0x11,0x38,0x30,0x32,0x31,0x78,0x2E,
    0x65,0x78,0x65,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
  };
  /*   uint8_t ackShida[] = {                                //实达专有响应附加包
             0xFF,0xFF,0x37,0x77,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
             0x00,0x00,0x00,0x00,0x00,0x08,0x15,0x00,0x00,0x13,0x11,0x38,0x30,0x32,0x31,0x78,
             0x2E,0x65,0x78,0x65,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
             0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x1F,0x00,0x00,0x00,
             0x00,0x00,0x13,0x11,0x00,0x28,0x1A,0x28,0x00,0x00,0x13,0x11,0x17,0x22,0x92,0x68,
             0x64,0x66,0x92,0x94,0x62,0x66,0x91,0x93,0x95,0x62,0x93,0x93,0x91,0x94,0x64,0x61,
             0x64,0x64,0x65,0x66,0x68,0x94,0x98,0xA7,0x61,0x67,0x65,0x67,0x9C,0x6B};*/

  static uint8_t ackShida[] =                                  //新版本的附加数据
  {
    0xff, 0xff, 0x37, 0x77, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0xc7, 0x04, 0x00, 0x00, 0x13, 0x11, 0x38, 0x30, 0x32, 0x31, 0x78,
    0x2e, 0x65, 0x78, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
    0x00, 0x00, 0x13, 0x11, 0x00, 0x28, 0x1a, 0x28, 0x00, 0x00, 0x13, 0x11, 0x17, 0x22, 0x96, 0x96,
    0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x67, 0x61, 0x96, 0x96, 0x64, 0x62,
    0x67, 0x91, 0x96, 0x96, 0x96, 0x96, 0x9e, 0xc9, 0xcd, 0x96, 0x67, 0x67, 0x98, 0x96, 0x00, 0x00,
    0x13, 0x11, 0x18, 0x06, 0x02, 0x00, 0x00, 0x00
  };

  unsigned char   md5Data[256]; //密码,md5 buffer
  unsigned char  *md5Dig;       //result of md5 sum
  int             md5Len=0;

  int nameLen,passwordLen;

  nameLen=strlen(config->userName);
  passwordLen=strlen(config->passWord);

  memcpy(ackPackage,this->destMac,6);
  memcpy(ackPackage+6,this->localMac,6); //将本机MAC地址填入组织回复的包

  ackPackage[0x12] = 0x02;                //code,2代表应答
  ackPackage[0x13]=pkt_data[0x13];        //id
  *(ackPackage+0x16) = *(pkt_data+0x16);  //type，即应答方式,HERE should alway be 4

  *(short *)(ackPackage+0x10) = htons((short)( 22+nameLen)); //len
  *(short *)(ackPackage+0x14) = *(short *)( ackPackage+0x10 );

  md5Data[md5Len++] = ackPackage[0x13];//ID
  memcpy(md5Data+md5Len,config->passWord,passwordLen);
  md5Len+=passwordLen; //密码
  memcpy(md5Data+md5Len,pkt_data+0x18,pkt_data[0x17]);
  md5Len+=pkt_data[0x17]; //密匙

  md5Dig =MD5::ComputeHash( md5Data, md5Len);

  ackPackage[0x17]=16;               //length of md5sum is always 16.
  memcpy(ackPackage+0x18,md5Dig,16);

  memcpy(ackPackage+0x28,config->userName,nameLen);

  FillNetParamater( &ackShida[0x05] );
  memcpy(ackPackage+0x28+nameLen,ackShida,120);
//   memcpy(ackPackage+0x28+nameLen,ackShida,0x6e);

  cout<<">> Sending password... "<<endl;
  OutPut(">> Sending password...");
  return (libnet_write_link(l,ackPackage, 0x3E8)==0x3E8)?0:-1;
}

int StarAuth::SendEchoPacket(libnet_t *l){
  static uint8_t echoPackage[] =          //echo包，用于每5秒钟激活一次
  {
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x88,0x8E,0x01,0xBF,
    0x00,0x1E,0xFF,0xFF,0x37,0x77,0x7F,0x9F,0xF7,0xFF,0x00,0x00,0xFF,0xFF,0x37,0x77,
    0x7F,0x9F,0xF7,0xFF,0x00,0x00,0xFF,0xFF,0x37,0x77,0x7F,0x3F,0xFF
  };

  Union32 uCrypt1,uCrypt2,uCrypt1_After,uCrypt2_After;

  serialNo.ulValue++;
  //m_serialNo is initialized at the beginning of main() of mystar.c, and
  //m_key is initialized in mystar.c when the 1st Authentication-Success packet is received.

  uCrypt1.ulValue = key.ulValue + serialNo.ulValue;
  uCrypt2.ulValue = serialNo.ulValue;

  memcpy( echoPackage, destMac, 6 );
  memcpy( echoPackage+6, localMac, 6 );

  uCrypt1_After.ulValue = htonl( uCrypt1.ulValue );
  uCrypt2_After.ulValue = htonl( uCrypt2.ulValue );

  echoPackage[0x18] = ByteTransform(uCrypt1_After.btValue[0]);
  echoPackage[0x19] = ByteTransform(uCrypt1_After.btValue[1]);
  echoPackage[0x1a] = ByteTransform(uCrypt1_After.btValue[2]);
  echoPackage[0x1b] = ByteTransform(uCrypt1_After.btValue[3]);
  echoPackage[0x22] = ByteTransform(uCrypt2_After.btValue[0]);
  echoPackage[0x23] = ByteTransform(uCrypt2_After.btValue[1]);
  echoPackage[0x24] = ByteTransform(uCrypt2_After.btValue[2]);
  echoPackage[0x25] = ByteTransform(uCrypt2_After.btValue[3]);

  return (libnet_write_link(l,echoPackage, 0x2d)==0x2d)?0:-1;
}

int  StarAuth::SendEndCertPacket(libnet_t *l){
  static uint8_t ExitPacket[]=
  {
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x88,0x8E,0x01,0x02,
    0x00,0x00,0xFF,0xFF,0x37,0x77,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x15,0x00,0x00,0x13,0x11,0x38,0x30,0x32,
    0x31,0x78,0x2E,0x65,0x78,0x65,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x1F,0x00,
    0x00,0x01,0x00,0x00,0x13,0x11,0x00,0x28,0x1A,0x28,0x00,0x00,0x13,0x11,0x17,0x22,
    0x64,0x91,0x60,0x60,0x65,0x65,0x69,0x61,0x64,0x64,0x94,0x93,0x91,0x92,0x96,0x65,
    0x95,0x64,0x68,0x91,0x62,0x68,0x62,0x94,0x9A,0xD6,0x94,0x68,0x66,0x69,0x6C,0x65
  };

  memcpy( ExitPacket, destMac, 6 );
  memcpy( ExitPacket+6,localMac, 6 );

  FillNetParamater( &ExitPacket[0x17] );

   cout<<">> Logouting... "<<endl;
   OutPut(">> Logouting...");
  return (libnet_write_link(l,ExitPacket,0x80)==0x80)?0:-1;

}
